﻿Imports AutoCAD

Public Class CadEntityDataServiceImpl
    Implements ICadEntityDataService

    Public Function IsPart(ByRef ent As AcadEntity) As Boolean Implements ICadEntityDataService.IsPart
        Return IsPart(ent.Layer, ent.ObjectName)
    End Function
    Public Function IsPart(layer As String, objectName As String) As Boolean Implements ICadEntityDataService.IsPart
        Return IsBlockReference(objectName) And layer.Equals("工件")
    End Function



    Public Function IsPlate(ByRef ent As AcadEntity) As Boolean Implements ICadEntityDataService.IsPlate
        Return IsPlate(ent.Layer, ent.ObjectName)
    End Function
    Public Function IsPlate(layer As String, objectName As String) As Boolean Implements ICadEntityDataService.IsPlate
        Return IsBlockReference(objectName) And layer.Equals("板件")
    End Function



    Public Function IsWork(ByRef ent As AcadEntity) As Boolean Implements ICadEntityDataService.IsWork
        Return ent.Layer = "加工"
    End Function



    Public Function IsBlockReference(ByRef ent As AcadEntity) As Boolean Implements ICadEntityDataService.IsBlockReference
        Return IsBlockReference(ent.ObjectName)
    End Function
    Public Function IsBlockReference(objectName As String) As Boolean Implements ICadEntityDataService.IsBlockReference
        Return objectName.Equals("AcDbBlockReference")
    End Function


    Public Function IsPolyline(ByRef ent As AcadEntity) As Boolean Implements ICadEntityDataService.IsPL
        Return IsPolyline(ent.ObjectName)
    End Function
    Public Function IsPolyline(objectName As String) As Boolean Implements ICadEntityDataService.IsPL
        Return objectName.Equals("AcDbPolyline")
    End Function


    Public Function IsCircle(ByRef ent As AcadEntity) As Boolean Implements ICadEntityDataService.IsCircle
        Return IsCircle(ent.ObjectName)
    End Function
    Public Function IsCircle(objectName As String) As Boolean Implements ICadEntityDataService.IsCircle
        Return objectName.Equals("AcDbCircle")
    End Function



    Public Function IsLine(ByRef ent As AcadEntity) As Boolean Implements ICadEntityDataService.IsLine
        Return IsLine(ent.ObjectName)
    End Function
    Public Function IsLine(objectName As String) As Boolean Implements ICadEntityDataService.IsLine
        Return objectName.Equals("AcDbLine")
    End Function


    Public Function IsArc(ByRef ent As AcadEntity) As Boolean Implements ICadEntityDataService.IsArc
        Return IsArc(ent.ObjectName)
    End Function

    Public Function IsArc(objectName As String) As Boolean Implements ICadEntityDataService.IsArc
        Return objectName.Equals("AcDbArc")
    End Function



    Public Function IsPoint(ByRef ent As AcadEntity) As Boolean Implements ICadEntityDataService.IsPoint
        Return IsPoint(ent.ObjectName)
    End Function

    Public Function IsPoint(objectName As String) As Boolean Implements ICadEntityDataService.IsPoint
        Return objectName.Equals("AcDbPoint")
    End Function



    Public Function IsSolid(ByRef ent As AcadEntity) As Boolean Implements ICadEntityDataService.IsSolid
        Return IsSolid(ent.ObjectName)
    End Function

    Public Function IsSolid(objectName As String) As Boolean Implements ICadEntityDataService.IsSolid
        Return objectName.Equals("AcDb3dSolid")
    End Function



    Public Function GetEntiyData(ByRef ents As IEnumerable) As DataTable Implements ICadEntityDataService.GetEntiyData
        Dim dt As DataTable = BuildDataTable_EntityData()

        Dim ent As AcadEntity
        Dim centroid() As Double
        Dim bbox(,) As Double
        Dim dr As DataRow
        For Each ent In ents
            dr = dt.NewRow
            dr("objectId") = ent.ObjectID
            dr("handle") = ent.Handle
            dr("layer") = ent.Layer
            dr("objectName") = ent.ObjectName

            bbox = GetBBox(ent)
            dr("minpX") = bbox(0, 0)
            dr("minpY") = bbox(0, 1)
            dr("minpZ") = bbox(0, 2)
            dr("maxpX") = bbox(1, 0)
            dr("maxpY") = bbox(1, 1)
            dr("maxpZ") = bbox(1, 2)

            centroid = GetCentroid(bbox)
            dr("centroidX") = centroid(0)
            dr("centroidY") = centroid(1)
            dr("centroidZ") = centroid(2)

            dt.Rows.Add(dr)
        Next
        Return dt
    End Function

    Private Function BuildDataTable_EntityData() As DataTable Implements ICadEntityDataService.BuildDataTable_EntityData
        Dim dt As New DataTable
        With dt.Columns
            .Add("objectId", GetType(Long))
            .Add("handle", GetType(String))
            .Add("layer", GetType(String))
            .Add("objectName", GetType(String))

            ' 质心
            .Add("centroidX", GetType(Double))
            .Add("centroidY", GetType(Double))
            .Add("centroidZ", GetType(Double))

            ' bbox
            .Add("minpX", GetType(Double))
            .Add("minpY", GetType(Double))
            .Add("minpZ", GetType(Double))

            .Add("maxpX", GetType(Double))
            .Add("maxpY", GetType(Double))
            .Add("maxpZ", GetType(Double))

        End With
        Return dt
    End Function



    Public Function GetCentroid(ByRef bbox As Double(,)) As Double() Implements ICadEntityDataService.GetCentroid
        Dim centroid(2) As Double
        centroid(0) = (bbox(0, 0) + bbox(1, 0)) / 2
        centroid(1) = (bbox(0, 1) + bbox(1, 1)) / 2
        centroid(2) = (bbox(0, 2) + bbox(1, 2)) / 2
        Return centroid
    End Function

    Public Function GetCentroid(ByRef ent As AcadEntity) As Double() Implements ICadEntityDataService.GetCentroid
        Dim bbox As Double(,) = GetBBox(ent)
        Return GetCentroid(bbox)
    End Function

    Public Function GetBBox(ByRef ent As AcadEntity) As Double(,) Implements ICadEntityDataService.GetBBox
        Dim minp, maxp
        ent.GetBoundingBox(minp, maxp)

        Dim bbox(1, 2) As Double
        bbox(0, 0) = minp(0)
        bbox(0, 1) = minp(1)
        bbox(0, 2) = minp(2)

        bbox(1, 0) = maxp(0)
        bbox(1, 1) = maxp(1)
        bbox(1, 2) = maxp(2)

        Return bbox
    End Function

    Public Function IsContain(ByRef centroid() As Double, ByRef bbox(,) As Double) As Object Implements ICadEntityDataService.IsContain
        Dim minp(2) As Double, maxp(2) As Double
        minp(0) = bbox(0, 0) : minp(1) = bbox(0, 1) : minp(2) = bbox(0, 2)
        minp(0) = bbox(1, 0) : minp(1) = bbox(1, 1) : minp(2) = bbox(1, 2)
        Return IsContain(minp, maxp, centroid)
    End Function

    Public Function IsContain(centroid() As Double, ByRef minp() As Double, ByRef maxp() As Double) As Object Implements ICadEntityDataService.IsContain
        Dim x As Double, y As Double, z As Double
        x = centroid(0) : y = centroid(1) : z = centroid(2)
        Return IsContain(x, y, z, minp, maxp)
    End Function

    Public Function IsContain(centroidX As Double, centroidY As Double, centroidZ As Double, ByRef minp() As Double, ByRef maxp() As Double) As Object Implements ICadEntityDataService.IsContain
        Return (centroidX >= minp(0) And centroidY >= minp(1) And centroidZ >= minp(2)) And (centroidX <= maxp(0) And centroidY <= maxp(1) And centroidZ <= maxp(2))
    End Function

    Public Function GetSize(ByRef ent As AcadEntity) As Object Implements ICadEntityDataService.GetSize
        Dim minp, maxp
        ent.GetBoundingBox(minp, maxp)
        Return GetSize(minp, maxp)
    End Function

    Public Function GetSize(ByRef minp() As Double, ByRef maxp() As Double) As Object Implements ICadEntityDataService.GetSize
        Return New Double() {maxp(0) - minp(0), maxp(1) - minp(1), maxp(2) - minp(2)}
    End Function

    ''' <summary>
    ''' 获取工件数据
    ''' </summary>
    ''' <param name="ents"></param>
    ''' <returns></returns>
    Public Function CreatePartDataTable(ByRef ents As IEnumerable) As DataTable Implements ICadEntityDataService.CreatePartDataTable

        Dim dt As DataTable = BuildDataTable_PartData()
        FillPartDataTable(dt, ents)
        Return dt
    End Function


    ''' <summary>
    ''' 填充到数据表
    ''' </summary>
    ''' <param name="dt"></param>
    ''' <param name="ents"></param>
    Public Sub FillPartDataTable(ByRef dt As DataTable, ByRef ents As IEnumerable) Implements ICadEntityDataService.FillPartDataTable
        Dim part As AcadBlockReference
        For Each ent As AcadEntity In ents
            If Not dt.Rows.Contains(ent.Handle) Then ' 跳过已存在句柄
                If IsPart(ent) Then
                    part = ent
                    dt.Rows.Add(BuildPartDataRow(dt, part))
                End If
            End If
        Next

    End Sub




    Function BuildPartDataRow(ByRef dt As DataTable, ByRef part As AcadBlockReference) As DataRow
        ' 复制part, 并获得尺寸
        Dim copyPart As AcadBlockReference = part.Copy
        With copyPart
            .Normal = New Double() {0, 0, 1}
            .Rotation = 0
            .InsertionPoint = New Double() {0, 0, 0}
        End With
        Dim size() As Double = GetSize(copyPart)
        copyPart.Delete()

        ' 填充数据
        Dim dr As DataRow = dt.NewRow
        With dr
            .Item("objectId") = part.ObjectID
            .Item("handle") = part.Handle
            .Item("layer") = part.Layer
            .Item("objectName") = part.ObjectName
            .Item("blockName") = part.EffectiveName
            .Item("groupName") = ""
            .Item("partName") = ""
            .Item("material") = ""
            .Item("edgeDesc") = ""
            .Item("sizeX") = Math.Round(size(0), 1)
            .Item("sizeY") = Math.Round(size(1), 1)
            .Item("sizeZ") = Math.Round(size(2), 1)
            .Item("remark") = ""
        End With

        Return dr
    End Function

    Public Function BuildDataTable_PartData() As DataTable Implements ICadEntityDataService.BuildDataTable_PartData
        Dim dt As New DataTable
        With dt.Columns
            .Add("objectId", GetType(Long))
            .Add("handle", GetType(String))
            .Add("layer", GetType(String))
            .Add("objectName", GetType(String))
            .Add("blockName", GetType(String)) '块名称

            ' 材质
            .Add("groupName", GetType(String)) '组名称
            .Add("partName", GetType(String)) '工件名称
            .Add("material", GetType(String)) '材质
            .Add("edgeDesc", GetType(String)) '封边说明

            ' 尺寸
            .Add("sizeX", GetType(Double)) '尺寸x
            .Add("sizeY", GetType(Double)) '尺寸y
            .Add("sizeZ", GetType(Double)) '尺寸z



            .Add("edge1", GetType(Double)).DefaultValue = 0 '封边厚度
            .Add("edge2", GetType(Double)).DefaultValue = 0 '封边厚度
            .Add("edge3", GetType(Double)).DefaultValue = 0 '封边厚度
            .Add("edge4", GetType(Double)).DefaultValue = 0 '封边厚度



            'Pre-milling
            .Add("pre_milling", GetType(Double)).DefaultValue = 0 '封边厚度

            .Add("cutX", GetType(Double), "sizeX - edge3 + pre_milling - edge4 + pre_milling") '开料x
            .Add("cutY", GetType(Double), "sizeX - edge1 + pre_milling - edge2  + pre_milling") '开料y
            .Add("cutZ", GetType(Double), "sizeZ") '开料z



            .Add("remark", GetType(String)) '加工备注
        End With
        dt.PrimaryKey = New DataColumn() {dt.Columns("handle")}

        Return dt
    End Function

    Public Function GetPartSize(ByRef part As AcadBlockReference) As Object Implements ICadEntityDataService.GetPartSize
        ' 复制part, 并获得尺寸
        Dim copyPart As AcadBlockReference = part.Copy
        With copyPart
            .Normal = New Double() {0, 0, 1}
            .Rotation = 0
            .InsertionPoint = New Double() {0, 0, 0}
        End With
        Dim size() As Double = GetSize(copyPart)
        copyPart.Delete()
        Return size
    End Function
End Class
